{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 5. 迭代器与生成器"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [],
   "source": [
    "import os\n",
    "import psutil\n",
    "\n",
    "# 显示当前 python 程序占用的内存大小\n",
    "def show_memory_info(hint):\n",
    "    pid = os.getpid()\n",
    "    p = psutil.Process(pid)\n",
    "    \n",
    "    info = p.memory_full_info()\n",
    "    memory = info.uss / 1024. / 1024\n",
    "    print('{} memory used: {} MB'.format(hint, memory))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "生成器是懒人版本的迭代器。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "initing iterator memory used: 52.4609375 MB\n",
      "after iterator initiated memory used: 3887.64453125 MB\n",
      "4999999950000000\n",
      "after sum called memory used: 3887.64453125 MB\n",
      "CPU times: total: 6.67 s\n",
      "Wall time: 6.67 s\n",
      "initing generator memory used: 55.6875 MB\n",
      "after generator initiated memory used: 55.6875 MB\n",
      "4999999950000000\n",
      "after sum called memory used: 55.6875 MB\n",
      "CPU times: total: 3.53 s\n",
      "Wall time: 3.53 s\n"
     ]
    }
   ],
   "source": [
    "def test_iterator():\n",
    "    show_memory_info('initing iterator')\n",
    "    list_1 = [i for i in range(100000000)]\n",
    "    show_memory_info('after iterator initiated')\n",
    "    print(sum(list_1))\n",
    "    show_memory_info('after sum called')\n",
    "\n",
    "def test_generator():\n",
    "    show_memory_info('initing generator')\n",
    "    list_2 = (i for i in range(100000000))\n",
    "    show_memory_info('after generator initiated')\n",
    "    print(sum(list_2))\n",
    "    show_memory_info('after sum called')\n",
    "\n",
    "%time test_iterator()\n",
    "%time test_generator()\n",
    "\n",
    "########## 输出 ##########\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 5.1 生成器"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "<generator object generator at 0x00000218C5D72BC0>\n",
      "<generator object generator at 0x00000218C5D72E00>\n",
      "next_1 = 1, next_3 = 1\n",
      "next_1 = 2, next_3 = 8\n",
      "next_1 = 3, next_3 = 27\n",
      "next_1 = 4, next_3 = 64\n",
      "next_1 = 5, next_3 = 125\n",
      "next_1 = 6, next_3 = 216\n",
      "next_1 = 7, next_3 = 343\n",
      "next_1 = 8, next_3 = 512\n",
      "1296 1296\n"
     ]
    }
   ],
   "source": [
    "\n",
    "\n",
    "def generator(k):\n",
    "    i = 1\n",
    "    while True:\n",
    "        yield i ** k\n",
    "        i += 1\n",
    "\n",
    "gen_1 = generator(1)\n",
    "gen_3 = generator(3)\n",
    "print(gen_1)\n",
    "print(gen_3)\n",
    "\n",
    "def get_sum(n):\n",
    "    sum_1, sum_3 = 0, 0\n",
    "    for i in range(n):\n",
    "        next_1 = next(gen_1)\n",
    "        next_3 = next(gen_3)\n",
    "        print('next_1 = {}, next_3 = {}'.format(next_1, next_3))\n",
    "        sum_1 += next_1\n",
    "        sum_3 += next_3\n",
    "    print(sum_1 * sum_1, sum_3)\n",
    "\n",
    "get_sum(8)\n",
    "\n",
    "########## 输出 ##########\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "2 2\n",
      "5 2\n",
      "9 2\n",
      "[2, 5, 9]\n"
     ]
    }
   ],
   "source": [
    "def index_normal(L, target):\n",
    "    result = []\n",
    "    for i, num in enumerate(L):\n",
    "        if num == target:\n",
    "            print(i,num)\n",
    "            result.append(i)\n",
    "    return result\n",
    "\n",
    "print(index_normal([1, 6, 2, 4, 5, 2, 8, 6, 3, 2], 2))\n",
    "\n",
    "########## 输出 ##########\n",
    "\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[2, 5, 9]\n"
     ]
    }
   ],
   "source": [
    "def index_generator(L, target):\n",
    "    for i, num in enumerate(L):\n",
    "        if num == target:\n",
    "            yield i\n",
    "\n",
    "print(list(index_generator([1, 6, 2, 4, 5, 2, 8, 6, 3, 2], 2)))\n",
    "\n",
    "########## 输出 ##########\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "True\n",
      "False\n"
     ]
    }
   ],
   "source": [
    "def is_subsequence(a, b):\n",
    "    b = iter(b)\n",
    "    return all(i in b for i in a)\n",
    "\n",
    "print(is_subsequence([1, 3, 5], [1, 2, 3, 4, 5]))\n",
    "print(is_subsequence([1, 4, 3], [1, 2, 3, 4, 5]))\n",
    "\n",
    "########## 输出 ##########\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 19,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "<list_iterator object at 0x00000218C5F564D0>\n",
      "<generator object is_subsequence.<locals>.<genexpr> at 0x00000218C5D73D00>\n",
      "1\n",
      "3\n",
      "5\n",
      "<generator object is_subsequence.<locals>.<genexpr> at 0x00000218C5F59700>\n",
      "True\n",
      "True\n",
      "True\n",
      "False\n",
      "<list_iterator object at 0x00000218C5F56770>\n",
      "<generator object is_subsequence.<locals>.<genexpr> at 0x00000218C5D73D00>\n",
      "1\n",
      "4\n",
      "3\n",
      "<generator object is_subsequence.<locals>.<genexpr> at 0x00000218C5F59700>\n",
      "True\n",
      "True\n",
      "False\n",
      "False\n"
     ]
    }
   ],
   "source": [
    "def is_subsequence(a, b):\n",
    "    b = iter(b)\n",
    "    print(b)\n",
    "\n",
    "    gen = (i for i in a)\n",
    "    print(gen)\n",
    "\n",
    "    for i in gen:\n",
    "        print(i)\n",
    "\n",
    "    gen = ((i in b) for i in a)\n",
    "    print(gen)\n",
    "\n",
    "    for i in gen:\n",
    "        print(i)\n",
    "\n",
    "    return all(((i in b) for i in a))\n",
    "\n",
    "print(is_subsequence([1, 3, 5], [1, 2, 3, 4, 5]))\n",
    "print(is_subsequence([1, 4, 3], [1, 2, 3, 4, 5]))\n",
    "\n",
    "########## 输出 ##########\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 总结\n",
    "\n",
    "- 容器是可迭代对象，可迭代对象调用 iter() 函数，可以得到一个迭代器。迭代器可以通过 next() 函数来得到下一个元素，从而支持遍历。\n",
    "\n",
    "- 生成器是一种特殊的迭代器（注意这个逻辑关系反之不成立）。使用生成器，你可以写出来更加清晰的代码；合理使用生成器，可以降低内存占用、优化程序结构、提高程序速度。\n",
    "\n",
    "- 生成器在 Python 2 的版本上，是协程的一种重要实现方式；而 Python 3.5 引入 async await 语法糖后，生成器实现协程的方式就已经落后了。我们会在下节课，继续深入讲解 Python 协程。"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.12.9"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
